/* ***** BEGIN LICENSE BLOCK *****
 *   Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Youtube Tooltip.
 *
 * The Initial Developer of the Original Code is
 * Brandon Peters.
 * Portions created by the Initial Developer are Copyright (C) 2008
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 * 
 * ***** END LICENSE BLOCK ***** */

var youtubetooltip = {
	prefs: null,
	showAuthor: false,
	showRating: false,
	showViews: false,
	showDuration: false,
	showDate: false,
	showDescription: false,
	showCategory: false,
	showTags: false,
	showComments: false,
	showResponses: false,

	originalTooltip: null,
	onLoad: function()
	{
		this.prefs = Components.classes["@mozilla.org/preferences-service;1"]
			.getService(Components.interfaces.nsIPrefService)
			.getBranch("extensions.{D48A12C2-E0F4-4640-8ADE-2DE4959E0F3D}.")
		this.prefs.QueryInterface(Components.interfaces.nsIPrefBranch2);
		this.prefs.addObserver("", this, false)

		this.showAuthor = this.prefs.getBoolPref("showauthor");
		this.showRating = this.prefs.getBoolPref("showrating");
		this.showViews = this.prefs.getBoolPref("showviews");
		this.showDuration = this.prefs.getBoolPref("showduration");
		this.showDate = this.prefs.getBoolPref("showdate");
		this.showDescription = this.prefs.getBoolPref("showdescription");
		this.showCategory = this.prefs.getBoolPref("showcategory");
		this.showTags = this.prefs.getBoolPref("showtags");
		this.showComments = this.prefs.getBoolPref("showcomments");
		this.showResponses = this.prefs.getBoolPref("showresponses");

		this.originalTooltip = window.FillInHTMLTooltip;
		window.FillInHTMLTooltip = this.newTooltip;
	},
	onUnload: function()
	{
		this.prefs.removeObserver("", this);
	},
	observe: function(subject, topic, data)
	{
		if(topic != "nsPref:changed")
		{
			return;
		}

		switch(data)
		{
			case "showauthor":
				this.showAuthor = this.prefs.getBoolPref("showauthor");
				break;
			case "showrating":
				this.showRating = this.prefs.getBoolPref("showrating");
				break;
			case "showviews":
				this.showViews = this.prefs.getBoolPref("showviews");
				break;
			case "showduration":
				this.showDuration = this.prefs.getBoolPref("showduration");
				break;
			case "showdate":
				this.showDate = this.prefs.getBoolPref("showdate");
				break;
			case "showdescription":
				this.showDescription = this.prefs.getBoolPref("showdescription");
				break;
			case "showcategory":
				this.showCategory = this.prefs.getBoolPref("showcategory");
				break;
			case "showtags":
				this.showTags = this.prefs.getBoolPref("showtags");
				break;
			case "showcomments":
				this.showComments = this.prefs.getBoolPref("showcomments");
				break;
			case "showresponses":
				this.showResponses = this.prefs.getBoolPref("showresponses");
				break;
		}
	},
	youtubeData: function(videoID)
	{
		var yData = [null, null, null, null, "", null, null, null, null, null, null];
		const xmlNS = "http://www.w3.org/2005/Atom";
		const ytNS = "http://gdata.youtube.com/schemas/2007"; 
		const gdNS = "http://schemas.google.com/g/2005";
		const mediaNS = "http://search.yahoo.com/mrss/";
		const osNS = "http://a9.com/-/spec/opensearchrss/1.0/";

		var gdataURL = "http://gdata.youtube.com/feeds/api/videos/" + videoID;
		var commentURL = "http://gdata.youtube.com/feeds/api/videos/" + videoID + "/comments";
		var responseURL = "http://gdata.youtube.com/feeds/api/videos/" + videoID + "/responses";

		var ioserv = Components.classes["@mozilla.org/network/io-service;1"] 
			.getService(Components.interfaces.nsIIOService); 
		var bstream = Components.classes["@mozilla.org/binaryinputstream;1"] 
			.createInstance(Components.interfaces.nsIBinaryInputStream); 
		var parser = new DOMParser();

		/* Video Entry */
		var videoChannel = ioserv.newChannel(gdataURL, 0, null); 
		var videoStream = videoChannel.open(); 

		if(videoChannel instanceof Components.interfaces.nsIHttpChannel && videoChannel.responseStatus != 200)
		{ 
			return yData;
		}

		bstream.setInputStream(videoStream); 

		var videoSize = 0;
		var videoFileData = ""; 
		while(videoSize = bstream.available())
		{ 
			videoFileData += bstream.readBytes(videoSize); 
		} 

		if(videoFileData == "")
		{
			return yData;
		}

		var videoDom = parser.parseFromString(videoFileData, "text/xml");

		/* Title */
		var titles = videoDom.getElementsByTagNameNS(xmlNS, "title");
		var titleElement = titles[0];
		if(titleElement.textContent)
		{
			yData[0] = titleElement.textContent;
		}

		/* Author */
		var authors = videoDom.getElementsByTagNameNS(xmlNS, "author");
		var authorElement = authors[0];
		var nameElement = authorElement.firstChild;
		if(nameElement.textContent)
		{
			yData[1] = nameElement.textContent;
		}

		/* Rating */
		var ratings = videoDom.getElementsByTagNameNS(gdNS, "rating");
		var ratingElement = ratings[0];
		if(ratingElement.getAttribute('average'))
		{
			yData[2] = ratingElement.getAttribute('average');
		}

		/* Number of Views */
		var views = videoDom.getElementsByTagNameNS(ytNS, "statistics");
		var viewElement = views[0];
		if(viewElement.getAttribute('viewCount'))
		{
			yData[3] = viewElement.getAttribute('viewCount');
		}

		/* Duration */
		var durations = videoDom.getElementsByTagNameNS(ytNS, "duration");
		var durationElement = durations[0];
		if(durationElement.getAttribute('seconds'))
		{
			var seconds = durationElement.getAttribute('seconds');
			var minutes = 0;
			var hours = 0;

			if(seconds > 60)
			{
				minutes = (seconds - (seconds % 60)) / 60;
				seconds = seconds % 60;
			}

			if(minutes > 60)
			{
				hours = (minutes - (minutes % 60)) / 60;
				minutes = minutes % 60;
			}

			if(hours != 0)
			{
				yData[4] += hours + "h";
			}

			if(minutes != 0)
			{
				yData[4] += minutes + "m";
			}

			if(seconds != 0)
			{
				yData[4] += seconds + "s";
			}
		}

		/* Date Published */
		var dates = videoDom.getElementsByTagNameNS(xmlNS, "published");
		var dateElement = dates[0];
		if(dateElement.textContent)
		{
			var re = "([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})";
			var dateStr = dateElement.textContent;
			var matches = dateStr.match(new RegExp(re));
			yData[5] = matches[2] + "/" + matches[3] + "/" + matches[1] + " " + matches[4] + ":" + matches[5] + ":" + matches[6];
		}

		/* Description */
		var descriptions = videoDom.getElementsByTagNameNS(xmlNS, "content");
		var descriptionElement = descriptions[0];
		if(descriptionElement.textContent)
		{
			yData[6] = descriptionElement.textContent;
		}
		
		/* Category */
		var categories = videoDom.getElementsByTagNameNS(mediaNS, "category");
		var categoryElement = categories[0];
		if(categoryElement.textContent)
		{
			yData[7] = categoryElement.textContent;
		}

		/* Tags */
		var tags = videoDom.getElementsByTagNameNS(mediaNS, "keywords");
		var tagElement = tags[0];
		if(tagElement.textContent)
		{
			yData[8] = tagElement.textContent;
		}

		/* Comments Entry */
		var commentChannel = ioserv.newChannel(commentURL, 0, null); 
		var commentStream = commentChannel.open(); 

		if(commentChannel instanceof Components.interfaces.nsIHttpChannel && commentChannel.responseStatus != 200)
		{ 
			return yData;
		}

		bstream.setInputStream(commentStream); 

		var commentSize = 0; 
		var commentFileData = ""; 
		while(commentSize = bstream.available())
		{ 
			commentFileData += bstream.readBytes(commentSize); 
		} 

		if(commentFileData == "")
		{
			return yData;
		}

		var commentDom = parser.parseFromString(commentFileData, "text/xml");

		/* Number of Comments */
		var comments = commentDom.getElementsByTagNameNS(osNS, "totalResults");
		var commentElement = comments[0];
		if(commentElement.textContent)
		{
			yData[9] = commentElement.textContent;
		}

		/* Responses Entry */
		var responseChannel = ioserv.newChannel(responseURL, 0, null); 
		var responseStream = responseChannel.open(); 

		if(responseChannel instanceof Components.interfaces.nsIHttpChannel && responseChannel.responseStatus != 200)
		{ 
			return yData;
		}

		bstream.setInputStream(responseStream); 

		var responseSize = 0; 
		var responseFileData = ""; 
		while(responseSize = bstream.available())
		{ 
			responseFileData += bstream.readBytes(responseSize); 
		} 

		if(responseFileData == "")
		{
			return yData;
		}

		var responseDom = parser.parseFromString(responseFileData, "text/xml");

		/* Number of Responses */
		var responses = responseDom.getElementsByTagNameNS(osNS, "totalResults");
		var responseElement = responses[0];
		if(responseElement.textContent)
		{
			yData[10] = responseElement.textContent;
		}

		return yData;
	},
	newTooltip: function(tipElement)
	{
		var retVal = false;

		if (tipElement.namespaceURI == "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul")
		{
			return retVal;
		}

		const XLinkNS = "http://www.w3.org/1999/xlink";

		var linkHREF = null;
		var XLinkHREF = null;

		var tipIter = tipElement;
		while(!linkHREF && !XLinkHREF && tipIter)
		{
			if(tipIter.nodeType == Node.ELEMENT_NODE)
			{
				linkHREF = tipIter.getAttribute("href");
				XLinkHREF = tipIter.getAttributeNS(XLinkNS, "href");
			}
			tipIter = tipIter.parentNode;
		}

		var hrefs = [linkHREF, XLinkHREF];
		var tipNode = document.getElementById("aHTMLTooltip");
		var re = /^http:\/\/([A-Za-z0-9]*)(\.?)youtube\.com\/watch\?v=([A-Za-z0-9-_]+)/;

		for(var i = 0; i < hrefs.length; ++i)
		{
			var h = hrefs[i];
			var hrefArray = null;
			if((hrefArray = re.exec(h)) != null)
			{
				var yID = hrefArray[3];
				var yData = youtubetooltip.youtubeData(yID);

				var tipLabel = yData[0];
				if(youtubetooltip.showAuthor)
				{
					tipLabel += "\nAuthor: " + yData[1];
				}

				if(youtubetooltip.showDuration)
				{
					tipLabel += "\nDuration: " + yData[4];
				}

				if(youtubetooltip.showRating)
				{
					tipLabel += "\nRating: " + yData[2];
				}

				if(youtubetooltip.showViews)
				{
					tipLabel += "\nViews: " + yData[3];
				}

				if(youtubetooltip.showDate)
				{
					tipLabel += "\nDate: " + yData[5];
				}

				if(youtubetooltip.showDescription)
				{
					tipLabel += "\nDescription: " + yData[6];
				}

				if(youtubetooltip.showCategory)
				{
					tipLabel += "\nCategory: " + yData[7];
				}

				if(youtubetooltip.showTags)
				{
					tipLabel += "\nTags: " + yData[8];
				}

				if(youtubetooltip.showComments)
				{
					tipLabel += "\nComments: " + yData[9];
				}

				if(youtubetooltip.showResponses)
				{
					tipLabel += "\nResponses: " + yData[10];
				}

				tipNode.setAttribute("label", tipLabel);
				tipNode.setAttribute("noautohide", true);

				if(tipLabel == null || yData[0] == null)
				{
					retVal = false;
				}
				else
				{
					retVal = true;
				}
			}
		}

		if(!retVal)
		{
			return youtubetooltip.originalTooltip(tipElement);
		}

		return retVal;
	},
};
window.addEventListener("load", function(e) { youtubetooltip.onLoad(e); }, false);
window.addEventListener("unload", function(e) { youtubetooltip.onUnload(e); }, false);
